/* * * * * * * * * * * * * * * * * * * * * *
*   Copyright (c) ycq_work@163.com
*   File:     MxgVector.h
*   Author:   ycq
*   e-mail：  ycq_work@163.com
*   Time:     2023-07-14
*   Description:
* * * * * * * * * * * * * * * * * * * * * * */

#ifndef MXGVECTOR_H
#define MXGVECTOR_H

#include <cstdarg>

namespace mxg::stl
{
template<typename T>
class vector
{
private:
    int _size{};                                  // 当前元素数量
    int _capacity{};                              // 容量
    T *_pAddr;

public:
    vector();

    explicit vector(int index);

    vector(vector<T> &other);

    vector(int count, const T &&data, ...);

    ~vector();

    // 元素访问
    T &front();

    T &back();

    T &operator[](int index);

    T &at(int index);

    vector<T> &operator=(const vector<T> &other);

    // Returns true if the container is empty. The return value should be checked and used.
    [[nodiscard]] bool empty() const;

    [[nodiscard]] int size() const;

    [[nodiscard]] int capacity() const;

    void push_back(T &data);

    void push_back(const T &data);

    void push_back(T &&data);

    void pop_back();

    // 扩容
    void reserve();

    // 释放未使用的内存, 优化内存
    void shrink_to_fit();

    void clear();

    void insert(int index, T &data);

    void insert(int index, const T &data);

    void insert(int index, const T &&data);

    void insert(int index, const vector<T> &other);

    void emplace(int index, T &data);

    void emplace(int index, const T &data);

    void emplace(int index, const T &&data);

    void emplace(int index, const vector<T> &other);

private:
    void try_init();

    void try_init(int capacity);

};

template<typename T>
vector<T>::vector()
{
    try_init();
}

template<typename T>
vector<T>::vector(int index)
{
    try_init(index);
}

template<typename T>
vector<T>::vector(vector<T> &other)
{
    try_init(other._size);
    *this = other;
}

template<typename T>
vector<T>::vector(const int count, const T &&data, ...)
{
    va_list args;
    va_start (args, data);

    if (this->_size < this->_capacity && this->_size == 0) {
        push_back(data);
    }

    for (int i = 1; i < count; ++i) {
        int value = va_arg (args, T);
        push_back(value);
    }

    va_end (args);
}

template<typename T>
vector<T>::~vector()
{
    if (this->_pAddr != nullptr) {
        delete[] this->_pAddr;
    }
}

template<typename T>
T &vector<T>::front()
{
    return this->_pAddr[0];
}

template<typename T>
T &vector<T>::back()
{
    if (this->_size == 0) {
        return this->_pAddr[this->_size];
    }
    return this->_pAddr[this->_size - 1];
}

template<typename T>
T &vector<T>::operator[](int index)
{
    return this->_pAddr[index];
}

template<typename T>
T &vector<T>::at(int index)
{
    return this->_pAddr[index];
}

template<typename T>
vector<T> &vector<T>::operator=(const vector<T> &other)
{
    if (this == &other) {
        return *this;
    }

    if (this->_capacity < other._capacity) {
        delete[] this->_pAddr;
        try_init(this->_capacity * 2);
    }

    for (int i = 0; i < other._size; ++i) {
        push_back(other._pAddr[i]);
    }

    return *this;
}

template<typename T>
bool vector<T>::empty() const
{
    return _size == 0;
}

template<typename T>
int vector<T>::size() const
{
    return _size;
}

template<typename T>
int vector<T>::capacity() const
{
    return _capacity;
}

template<typename T>
void vector<T>::push_back(T &data)
{
    if (this->_size <= this->_capacity) {
        reserve();
    }

    this->_pAddr[this->_size] = data;
    this->_size++;
}

template<typename T>
void vector<T>::push_back(const T &data)
{
    push_back(const_cast<T &>(data));
}

template<typename T>
void vector<T>::push_back(T &&data)
{
    push_back(data);
}

template<typename T>
void vector<T>::pop_back()
{
    if (this->_size <= 0) {
        return;
    }
    // 变成一个无意义的值
    this->_pAddr[this->_size - 1] = -999999;
    this->_size--;
}

template<typename T>
void vector<T>::reserve()
{
    if (_size < _capacity)
        return;

    int new_capacity = (_capacity == 0) ? 1 : _capacity * 2;
    T *new_pAddr = new T[new_capacity];

    for (int i = 0; i < _size; ++i) {
        new_pAddr[i] = _pAddr[i];
    }

    delete[] this->_pAddr;
    this->_pAddr = new_pAddr;
    this->_capacity = new_capacity;
}

template<typename T>
void vector<T>::shrink_to_fit()
{
    if (_size < _capacity) {
        T *new_pAddr = new T[_size];
        for (int i = 0; i < _size; ++i) {
            new_pAddr[i] = _pAddr[i];
        }
        delete[] _pAddr;
        _pAddr = new_pAddr;
        _capacity = _size;
    }
}

template<typename T>
void vector<T>::clear()
{
    _size = 0;
}

template<typename T>
void vector<T>::insert(const int index, T &data)
{
    // 位置非法
    if (index < 0 || index > this->_size) {
        return;
    }

    // 容量不够, 则扩容
    if (this->_size >= this->_capacity) {
        reserve();
    }

    for (int i = _size; i > index; i--) {
        this->_pAddr[i] = this->_pAddr[i - 1];
    }

    this->_pAddr[index] = data;

    _size++;
}

template<typename T>
void vector<T>::insert(const int index, const T &data)
{
    insert(index, const_cast<T &>(data));
}

template<typename T>
void vector<T>::insert(const int index, const T &&data)
{
    insert(index, const_cast<T &>(data));
}

template<typename T>
void vector<T>::insert(const int index, const vector<T> &other)
{
    if (other._size == 0) {
        return;
    }

    // 位置非法
    if (index < 0 || index > this->_size) {
        return;
    }

    T *temp = new T[this->_size + other._size];

    for (int i = 0; i < index; ++i) {
        temp[i] = _pAddr[i];
    }

    for (int i = 0; i < other._size; ++i) {
        temp[index + i] = other._pAddr[i];
    }

    for (int i = index; i < _size; ++i) {
        temp[other._size + i] = _pAddr[i];
    }

    delete[] this->_pAddr;

    this->_pAddr = temp;

    this->_size += other._size;

    this->_capacity += other._size;
}

template<typename T>
void vector<T>::emplace(const int index, T &data)
{
    insert(index - 1, data);
}

template<typename T>
void vector<T>::emplace(const int index, const T &data)
{
    insert(index - 1, data);
}

template<typename T>
void vector<T>::emplace(const int index, const T &&data)
{
    insert(index - 1, data);
}

template<typename T>
void vector<T>::emplace(const int index, const vector<T> &other)
{
    insert(index - 1, other);
}

template<typename T>
void vector<T>::try_init()
{
    this->_size = 0;
    this->_capacity = 0;
    _pAddr = nullptr;
}

// 创建数组
template<typename T>
void vector<T>::try_init(int capacity)
{
    this->_capacity = capacity;
    this->_size = 0;
    // 申请内存
    this->_pAddr = new T[this->_capacity];
}

} // namespace mxg::stl

#endif // MXGVECTOR_H
